source('../env.R')
Using GitHub PAT from the git credential store.
Skipping install of 'clootl' from a github remote, the SHA1 (30ac57ee) has not changed since last install.
  Use `force = TRUE` to force installation

Create dataset

Load community data

communities = read_csv(filename(COMMUNITY_OUTPUT_DIR, 'communities_for_analysis.csv'))
Rows: 2428 Columns: 7── Column specification ────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): city_name, ebird_species_name, seasonal, presence, origin
dbl (2): city_id, relative_abundance_proxy
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
communities

Load trait data

traits = read_csv(filename(TAXONOMY_OUTPUT_DIR, 'traits_ebird.csv'))
Rows: 332 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): ebird_species_name, habitat, trophic_level, trophic_niche, primary_lifestyle
dbl (5): beak_width, hwi, mass, habitat_density, migration
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(traits)
species_urban_response = communities %>% group_by(ebird_species_name) %>% summarise(mean_relative_abundance_proxy = mean(relative_abundance_proxy)) %>% left_join(traits)
Joining with `by = join_by(ebird_species_name)`
species_urban_response$is_urban = species_urban_response$mean_relative_abundance_proxy > 0
species_urban_response$ebird_species_name = str_replace(species_urban_response$ebird_species_name,' ', '_')
species_urban_response

Most urban species

species_urban_response %>% filter(mean_relative_abundance_proxy > 50)
species_urban_response %>% filter(mean_relative_abundance_proxy > 40)
species_urban_response %>% filter(mean_relative_abundance_proxy > 30)

Difference amongst urban and non-urban

species_urban_response %>% group_by(is_urban) %>% summarise(
  median_beak_width = median(beak_width),
  iqr_beak_width = IQR(beak_width),
  
  median_hwi = median(hwi),
  iqr_hwi = IQR(hwi),
  
  median_mass = median(mass),
  iqr_mass = IQR(mass),
  
  n = n()
)

Compare traits between urban and non-urban species

Gape Width

ggplot(species_urban_response, aes(x = is_urban, y = beak_width)) + geom_boxplot()

wilcox.test(beak_width ~ is_urban, species_urban_response)

    Wilcoxon rank sum test with continuity correction

data:  beak_width by is_urban
W = 1525, p-value = 0.3893
alternative hypothesis: true location shift is not equal to 0

There is not a significant response for the gape width between urban species and non urban species.

HWI

ggplot(species_urban_response, aes(x = is_urban, y = hwi)) + geom_boxplot()

wilcox.test(hwi ~ is_urban, species_urban_response)

    Wilcoxon rank sum test with continuity correction

data:  hwi by is_urban
W = 1213, p-value = 0.01492
alternative hypothesis: true location shift is not equal to 0

There is a significant response between urban and non-urban species

Mass

ggplot(species_urban_response, aes(x = is_urban, y = mass)) + geom_boxplot()

wilcox.test(mass ~ is_urban, species_urban_response)

    Wilcoxon rank sum test with continuity correction

data:  mass by is_urban
W = 1825, p-value = 0.5168
alternative hypothesis: true location shift is not equal to 0

There is not a significant response between species.

Phylogeny

Phylogentic response to relative abundance?

tree = read.tree(filename(TAXONOMY_OUTPUT_DIR, 'phylogeny.tre'))
tree_pruned = ladderize(drop.tip(tree, setdiff(tree$tip.label, species_urban_response$ebird_species_name)))
ggtree(tree_pruned, layout="fan")
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.

columbidae_response <- species_urban_response$mean_relative_abundance_proxy
names(columbidae_response) <- species_urban_response$ebird_species_name

Is the a phylogenetic signal for our relative abundance proxy

col_ut_phylo_signal <- phylosig(tree_pruned, columbidae_response, method="lambda", test=TRUE)
col_ut_phylo_signal

Phylogenetic signal lambda : 0.46832 
logL(lambda) : -576.839 
LR(lambda=0) : 7.45324 
P-value (based on LR test) : 0.00633224 

Plot tree

species_urban_response$ebird_species_name_clean = gsub("_", " ", species_urban_response$ebird_species_name)

normalize <- function(x) (x - min(x)) / (max(x) - min(x)) * 5 + 1  # Scale to range [1, 6]
species_urban_response$beak_width_norm <- normalize(species_urban_response$beak_width)
species_urban_response$hwi_norm <- normalize(species_urban_response$hwi)
species_urban_response$mass_norm <- normalize(species_urban_response$mass)

g = ggtree(tree_pruned, layout="fan") %<+% species_urban_response + abundance_proxy_scale
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.
g + 
  geom_fruit(geom = geom_point, mapping = aes(size = beak_width_norm), fill = beak_width_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0, show.legend = FALSE) + 
  geom_fruit(geom = geom_point, mapping = aes(size = hwi_norm), fill = hwi_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0.13, show.legend = FALSE) + 
  geom_fruit(geom = geom_point, mapping = aes(size = mass_norm), fill = mass_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0.15, show.legend = FALSE) + 
  geom_tiplab(size=2, aes(label=ebird_species_name_clean, color = mean_relative_abundance_proxy), offset = 15) +
  labs(color = "Mean relative abundance proxy") + 
  theme(legend.position = "bottom") + ggplot2::xlim(0, 80)

ggsave(filename(FIGURES_OUTPUT_DIR, 'phylogeny.jpg'), width = 2000, height = 2100, units = 'px')

Format plot for nature

g_fig_base = ggtree(tree_pruned, layout="fan") %<+% species_urban_response
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.
g_fig = g_fig_base + 
  geom_fruit(geom = geom_point, mapping = aes(size = beak_width_norm), fill = beak_width_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0, show.legend = FALSE) + 
  geom_fruit(geom = geom_point, mapping = aes(size = hwi_norm), fill = hwi_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0.13, show.legend = FALSE) + 
  geom_fruit(geom = geom_point, mapping = aes(size = mass_norm), fill = mass_colour, colour = 'black', shape = 21, stroke = 0.2, offset = 0.15, show.legend = FALSE) + 
  geom_tiplab(size=2, aes(label=ebird_species_name_clean), offset = 30)

heatmap_fig_ata = data.frame(species_urban_response[, "mean_relative_abundance_proxy"])
colnames(heatmap_fig_ata) = c('MRAP')
rownames(heatmap_fig_ata) = species_urban_response$ebird_species_name

gheatmap(g_fig, 
         heatmap_fig_ata, 
         offset = 14, 
         width = 0.2,
         colnames_angle = 0, 
         colnames_offset_x = 0.5, 
         font.size = 3) + 
  abundance_proxy_scale_fill + 
  labs(fill = "MRAP (Mean relative abundance proxy)") + 
  theme(legend.position = "bottom") + 
  ggplot2::xlim(0, 85)
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
ggsave(filename(FIGURES_OUTPUT_DIR, 'figure3.jpg'), width = 180, height = 200, units = 'mm', dpi = 450)

Plot traits against abundance proxy

cut_off_3 = 50
cut_off_2 = 35
cut_off_1 = 1

hwi_by_mass_urban_3 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_3) %>% slice(chull(hwi, mass))
hwi_by_mass_urban_2 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_2) %>% slice(chull(hwi, mass))
hwi_by_mass_urban_1 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_1) %>% slice(chull(hwi, mass))

beak_width_by_mass_urban_3 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_3) %>% slice(chull(beak_width, mass))
beak_width_by_mass_urban_2 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_2) %>% slice(chull(beak_width, mass))
beak_width_by_mass_urban_1 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_1) %>% slice(chull(beak_width, mass))

hwi_by_beak_width_urban_3 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_3) %>% slice(chull(hwi, beak_width))
hwi_by_beak_width_urban_2 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_2) %>% slice(chull(hwi, beak_width))
hwi_by_beak_width_urban_1 = species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_1) %>% slice(chull(hwi, beak_width))

species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_3) %>% nrow()
species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_2) %>% nrow()
species_urban_response %>% filter(mean_relative_abundance_proxy > cut_off_1) %>% nrow()
polygon_line_type = 'dashed'
polygon_linewidth = 0.4
polygon_alpha1 = 0.05
polygon_alpha2 = 0.1
polygon_alpha3 = 0.15

hwi_by_mass = ggplot(species_urban_response, aes(x = hwi, y = mass, colour = mean_relative_abundance_proxy)) + 
  geom_polygon(data = hwi_by_mass_urban_1, alpha = polygon_alpha1, color = trait_polygon_light, fill = trait_polygon_light, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = hwi_by_mass_urban_2, alpha = polygon_alpha2, color = trait_polygon_med, fill = trait_polygon_med, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = hwi_by_mass_urban_3, alpha = polygon_alpha3, color = trait_polygon_dark, fill = trait_polygon_dark, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_point() + 
  abundance_proxy_scale +
  labs(colour = "Mean relative abundance proxy", y = 'Mass', x = '') + 
  theme(legend.position = 'bottom', legend.title.position = 'top', legend.key.width = unit(12, 'mm'))

beak_width_by_mass = ggplot(species_urban_response, aes(x = beak_width, y = mass, colour = mean_relative_abundance_proxy)) + 
  geom_polygon(data = beak_width_by_mass_urban_1, alpha = polygon_alpha1, color = trait_polygon_light, fill = trait_polygon_light, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = beak_width_by_mass_urban_2, alpha = polygon_alpha2, color = trait_polygon_med, fill = trait_polygon_med, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = beak_width_by_mass_urban_3, alpha = polygon_alpha3, color = trait_polygon_dark, fill = trait_polygon_dark, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_point() + 
  abundance_proxy_scale + 
  labs(y = '', x = 'Beak width')

hwi_by_beak_width = ggplot(species_urban_response, aes(x = hwi, y = beak_width, colour = mean_relative_abundance_proxy)) + 
  geom_polygon(data = hwi_by_beak_width_urban_1, alpha = polygon_alpha1, color = trait_polygon_light, fill = trait_polygon_light, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = hwi_by_beak_width_urban_2, alpha = polygon_alpha2, color = trait_polygon_med, fill = trait_polygon_med, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_polygon(data = hwi_by_beak_width_urban_3, alpha = polygon_alpha3, color = trait_polygon_dark, fill = trait_polygon_dark, linewidth = polygon_linewidth, linetype = polygon_line_type) +
  geom_point() + 
  abundance_proxy_scale + 
  labs(y = 'Beak width', x = 'HWI')

legend <- ggpubr::get_legend(
  # create some space to the left of the legend
  hwi_by_mass
)

plot_grid(
  nrow = 2, ncol = 2,
  hwi_by_mass + theme(legend.position="none"),
  beak_width_by_mass + theme(legend.position="none"),
  hwi_by_beak_width + theme(legend.position="none"),
  legend
)

ggsave(filename(FIGURES_OUTPUT_DIR, 'traits.jpg'), width = 2000, height = 1800, units = 'px')
LS0tCnRpdGxlOiAiQ29tcGFyZSB1cmJhbiB0cmFpdHMgYW5kIHBoeWxvZ2VuY3kiCm91dHB1dDogaHRtbF9ub3RlYm9vawpiaWJsaW9ncmFwaHk6IC4uL3JlZi5iaWIgIAotLS0KCmBgYHtyfQpzb3VyY2UoJy4uL2Vudi5SJykKYGBgCiMgQ3JlYXRlIGRhdGFzZXQKCkxvYWQgY29tbXVuaXR5IGRhdGEKYGBge3J9CmNvbW11bml0aWVzID0gcmVhZF9jc3YoZmlsZW5hbWUoQ09NTVVOSVRZX09VVFBVVF9ESVIsICdjb21tdW5pdGllc19mb3JfYW5hbHlzaXMuY3N2JykpCmNvbW11bml0aWVzCmBgYAoKTG9hZCB0cmFpdCBkYXRhCmBgYHtyfQp0cmFpdHMgPSByZWFkX2NzdihmaWxlbmFtZShUQVhPTk9NWV9PVVRQVVRfRElSLCAndHJhaXRzX2ViaXJkLmNzdicpKQpoZWFkKHRyYWl0cykKYGBgCgpgYGB7cn0Kc3BlY2llc191cmJhbl9yZXNwb25zZSA9IGNvbW11bml0aWVzICU+JSBncm91cF9ieShlYmlyZF9zcGVjaWVzX25hbWUpICU+JSBzdW1tYXJpc2UobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPSBtZWFuKHJlbGF0aXZlX2FidW5kYW5jZV9wcm94eSkpICU+JSBsZWZ0X2pvaW4odHJhaXRzKQpzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGlzX3VyYmFuID0gc3BlY2llc191cmJhbl9yZXNwb25zZSRtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSA+IDAKc3BlY2llc191cmJhbl9yZXNwb25zZSRlYmlyZF9zcGVjaWVzX25hbWUgPSBzdHJfcmVwbGFjZShzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGViaXJkX3NwZWNpZXNfbmFtZSwnICcsICdfJykKc3BlY2llc191cmJhbl9yZXNwb25zZQpgYGAKCiMjIE1vc3QgdXJiYW4gc3BlY2llcwpgYGB7cn0Kc3BlY2llc191cmJhbl9yZXNwb25zZSAlPiUgZmlsdGVyKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX3Byb3h5ID4gNTApCmBgYAoKYGBge3J9CnNwZWNpZXNfdXJiYW5fcmVzcG9uc2UgJT4lIGZpbHRlcihtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSA+IDQwKQpgYGAKCmBgYHtyfQpzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiAzMCkKYGBgCgojIyBEaWZmZXJlbmNlIGFtb25nc3QgdXJiYW4gYW5kIG5vbi11cmJhbgpgYGB7cn0Kc3BlY2llc191cmJhbl9yZXNwb25zZSAlPiUgZ3JvdXBfYnkoaXNfdXJiYW4pICU+JSBzdW1tYXJpc2UoCiAgbWVkaWFuX2JlYWtfd2lkdGggPSBtZWRpYW4oYmVha193aWR0aCksCiAgaXFyX2JlYWtfd2lkdGggPSBJUVIoYmVha193aWR0aCksCiAgCiAgbWVkaWFuX2h3aSA9IG1lZGlhbihod2kpLAogIGlxcl9od2kgPSBJUVIoaHdpKSwKICAKICBtZWRpYW5fbWFzcyA9IG1lZGlhbihtYXNzKSwKICBpcXJfbWFzcyA9IElRUihtYXNzKSwKICAKICBuID0gbigpCikKYGBgCgojIENvbXBhcmUgdHJhaXRzIGJldHdlZW4gdXJiYW4gYW5kIG5vbi11cmJhbiBzcGVjaWVzCgojIyBHYXBlIFdpZHRoCmBgYHtyfQpnZ3Bsb3Qoc3BlY2llc191cmJhbl9yZXNwb25zZSwgYWVzKHggPSBpc191cmJhbiwgeSA9IGJlYWtfd2lkdGgpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKYGBge3J9CndpbGNveC50ZXN0KGJlYWtfd2lkdGggfiBpc191cmJhbiwgc3BlY2llc191cmJhbl9yZXNwb25zZSkKYGBgClRoZXJlIGlzIG5vdCBhIHNpZ25pZmljYW50IHJlc3BvbnNlIGZvciB0aGUgZ2FwZSB3aWR0aCBiZXR3ZWVuIHVyYmFuIHNwZWNpZXMgYW5kIG5vbiB1cmJhbiBzcGVjaWVzLgoKIyMgSFdJCmBgYHtyfQpnZ3Bsb3Qoc3BlY2llc191cmJhbl9yZXNwb25zZSwgYWVzKHggPSBpc191cmJhbiwgeSA9IGh3aSkpICsgZ2VvbV9ib3hwbG90KCkKYGBgCgpgYGB7cn0Kd2lsY294LnRlc3QoaHdpIH4gaXNfdXJiYW4sIHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UpCmBgYApUaGVyZSBpcyBhIHNpZ25pZmljYW50IHJlc3BvbnNlIGJldHdlZW4gdXJiYW4gYW5kIG5vbi11cmJhbiBzcGVjaWVzCgojIyBNYXNzCgpgYGB7cn0KZ2dwbG90KHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UsIGFlcyh4ID0gaXNfdXJiYW4sIHkgPSBtYXNzKSkgKyBnZW9tX2JveHBsb3QoKQpgYGAKCmBgYHtyfQp3aWxjb3gudGVzdChtYXNzIH4gaXNfdXJiYW4sIHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UpCmBgYAoKVGhlcmUgaXMgbm90IGEgc2lnbmlmaWNhbnQgcmVzcG9uc2UgYmV0d2VlbiBzcGVjaWVzLgoKIyBQaHlsb2dlbnkKCiMjIFBoeWxvZ2VudGljIHJlc3BvbnNlIHRvIHJlbGF0aXZlIGFidW5kYW5jZT8KYGBge3J9CnRyZWUgPSByZWFkLnRyZWUoZmlsZW5hbWUoVEFYT05PTVlfT1VUUFVUX0RJUiwgJ3BoeWxvZ2VueS50cmUnKSkKdHJlZV9wcnVuZWQgPSBsYWRkZXJpemUoZHJvcC50aXAodHJlZSwgc2V0ZGlmZih0cmVlJHRpcC5sYWJlbCwgc3BlY2llc191cmJhbl9yZXNwb25zZSRlYmlyZF9zcGVjaWVzX25hbWUpKSkKZ2d0cmVlKHRyZWVfcHJ1bmVkLCBsYXlvdXQ9ImZhbiIpCmBgYAoKYGBge3J9CmNvbHVtYmlkYWVfcmVzcG9uc2UgPC0gc3BlY2llc191cmJhbl9yZXNwb25zZSRtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eQpuYW1lcyhjb2x1bWJpZGFlX3Jlc3BvbnNlKSA8LSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGViaXJkX3NwZWNpZXNfbmFtZQpgYGAKCklzIHRoZSBhIHBoeWxvZ2VuZXRpYyBzaWduYWwgZm9yIG91ciByZWxhdGl2ZSBhYnVuZGFuY2UgcHJveHkKYGBge3J9CmNvbF91dF9waHlsb19zaWduYWwgPC0gcGh5bG9zaWcodHJlZV9wcnVuZWQsIGNvbHVtYmlkYWVfcmVzcG9uc2UsIG1ldGhvZD0ibGFtYmRhIiwgdGVzdD1UUlVFKQpjb2xfdXRfcGh5bG9fc2lnbmFsCmBgYAoKIyMgUGxvdCB0cmVlCmBgYHtyfQpzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGViaXJkX3NwZWNpZXNfbmFtZV9jbGVhbiA9IGdzdWIoIl8iLCAiICIsIHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UkZWJpcmRfc3BlY2llc19uYW1lKQoKbm9ybWFsaXplIDwtIGZ1bmN0aW9uKHgpICh4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpICogNSArIDEgICMgU2NhbGUgdG8gcmFuZ2UgWzEsIDZdCnNwZWNpZXNfdXJiYW5fcmVzcG9uc2UkYmVha193aWR0aF9ub3JtIDwtIG5vcm1hbGl6ZShzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGJlYWtfd2lkdGgpCnNwZWNpZXNfdXJiYW5fcmVzcG9uc2UkaHdpX25vcm0gPC0gbm9ybWFsaXplKHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UkaHdpKQpzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJG1hc3Nfbm9ybSA8LSBub3JtYWxpemUoc3BlY2llc191cmJhbl9yZXNwb25zZSRtYXNzKQoKZyA9IGdndHJlZSh0cmVlX3BydW5lZCwgbGF5b3V0PSJmYW4iKSAlPCslIHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UgKyBhYnVuZGFuY2VfcHJveHlfc2NhbGUKZyArIAogIGdlb21fZnJ1aXQoZ2VvbSA9IGdlb21fcG9pbnQsIG1hcHBpbmcgPSBhZXMoc2l6ZSA9IGJlYWtfd2lkdGhfbm9ybSksIGZpbGwgPSBiZWFrX3dpZHRoX2NvbG91ciwgY29sb3VyID0gJ2JsYWNrJywgc2hhcGUgPSAyMSwgc3Ryb2tlID0gMC4yLCBvZmZzZXQgPSAwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fZnJ1aXQoZ2VvbSA9IGdlb21fcG9pbnQsIG1hcHBpbmcgPSBhZXMoc2l6ZSA9IGh3aV9ub3JtKSwgZmlsbCA9IGh3aV9jb2xvdXIsIGNvbG91ciA9ICdibGFjaycsIHNoYXBlID0gMjEsIHN0cm9rZSA9IDAuMiwgb2Zmc2V0ID0gMC4xMywgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2ZydWl0KGdlb20gPSBnZW9tX3BvaW50LCBtYXBwaW5nID0gYWVzKHNpemUgPSBtYXNzX25vcm0pLCBmaWxsID0gbWFzc19jb2xvdXIsIGNvbG91ciA9ICdibGFjaycsIHNoYXBlID0gMjEsIHN0cm9rZSA9IDAuMiwgb2Zmc2V0ID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX3RpcGxhYihzaXplPTIsIGFlcyhsYWJlbD1lYmlyZF9zcGVjaWVzX25hbWVfY2xlYW4sIGNvbG9yID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkpLCBvZmZzZXQgPSAxNSkgKwogIGxhYnMoY29sb3IgPSAiTWVhbiByZWxhdGl2ZSBhYnVuZGFuY2UgcHJveHkiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArIGdncGxvdDI6OnhsaW0oMCwgODApCgpnZ3NhdmUoZmlsZW5hbWUoRklHVVJFU19PVVRQVVRfRElSLCAncGh5bG9nZW55LmpwZycpLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDIxMDAsIHVuaXRzID0gJ3B4JykKYGBgCkZvcm1hdCBwbG90IGZvciBuYXR1cmUKYGBge3J9CmdfZmlnX2Jhc2UgPSBnZ3RyZWUodHJlZV9wcnVuZWQsIGxheW91dD0iZmFuIikgJTwrJSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlCmdfZmlnID0gZ19maWdfYmFzZSArIAogIGdlb21fZnJ1aXQoZ2VvbSA9IGdlb21fcG9pbnQsIG1hcHBpbmcgPSBhZXMoc2l6ZSA9IGJlYWtfd2lkdGhfbm9ybSksIGZpbGwgPSBiZWFrX3dpZHRoX2NvbG91ciwgY29sb3VyID0gJ2JsYWNrJywgc2hhcGUgPSAyMSwgc3Ryb2tlID0gMC4yLCBvZmZzZXQgPSAwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fZnJ1aXQoZ2VvbSA9IGdlb21fcG9pbnQsIG1hcHBpbmcgPSBhZXMoc2l6ZSA9IGh3aV9ub3JtKSwgZmlsbCA9IGh3aV9jb2xvdXIsIGNvbG91ciA9ICdibGFjaycsIHNoYXBlID0gMjEsIHN0cm9rZSA9IDAuMiwgb2Zmc2V0ID0gMC4xMywgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2ZydWl0KGdlb20gPSBnZW9tX3BvaW50LCBtYXBwaW5nID0gYWVzKHNpemUgPSBtYXNzX25vcm0pLCBmaWxsID0gbWFzc19jb2xvdXIsIGNvbG91ciA9ICdibGFjaycsIHNoYXBlID0gMjEsIHN0cm9rZSA9IDAuMiwgb2Zmc2V0ID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX3RpcGxhYihzaXplPTIsIGFlcyhsYWJlbD1lYmlyZF9zcGVjaWVzX25hbWVfY2xlYW4pLCBvZmZzZXQgPSAzMCkKCmhlYXRtYXBfZmlnX2F0YSA9IGRhdGEuZnJhbWUoc3BlY2llc191cmJhbl9yZXNwb25zZVssICJtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSJdKQpjb2xuYW1lcyhoZWF0bWFwX2ZpZ19hdGEpID0gYygnTVJBUCcpCnJvd25hbWVzKGhlYXRtYXBfZmlnX2F0YSkgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlJGViaXJkX3NwZWNpZXNfbmFtZQoKZ2hlYXRtYXAoZ19maWcsIAogICAgICAgICBoZWF0bWFwX2ZpZ19hdGEsIAogICAgICAgICBvZmZzZXQgPSAxNCwgCiAgICAgICAgIHdpZHRoID0gMC4yLAogICAgICAgICBjb2xuYW1lc19hbmdsZSA9IDAsIAogICAgICAgICBjb2xuYW1lc19vZmZzZXRfeCA9IDAuNSwgCiAgICAgICAgIGZvbnQuc2l6ZSA9IDMpICsgCiAgYWJ1bmRhbmNlX3Byb3h5X3NjYWxlX2ZpbGwgKyAKICBsYWJzKGZpbGwgPSAiTVJBUCAoTWVhbiByZWxhdGl2ZSBhYnVuZGFuY2UgcHJveHkpIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyAKICBnZ3Bsb3QyOjp4bGltKDAsIDg1KQoKZ2dzYXZlKGZpbGVuYW1lKEZJR1VSRVNfT1VUUFVUX0RJUiwgJ2ZpZ3VyZTMuanBnJyksIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAyMDAsIHVuaXRzID0gJ21tJywgZHBpID0gNDUwKQpgYGAKCiMjIFBsb3QgdHJhaXRzIGFnYWluc3QgYWJ1bmRhbmNlIHByb3h5CmBgYHtyfQpjdXRfb2ZmXzMgPSA1MApjdXRfb2ZmXzIgPSAzNQpjdXRfb2ZmXzEgPSAxCgpod2lfYnlfbWFzc191cmJhbl8zID0gc3BlY2llc191cmJhbl9yZXNwb25zZSAlPiUgZmlsdGVyKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX3Byb3h5ID4gY3V0X29mZl8zKSAlPiUgc2xpY2UoY2h1bGwoaHdpLCBtYXNzKSkKaHdpX2J5X21hc3NfdXJiYW5fMiA9IHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UgJT4lIGZpbHRlcihtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSA+IGN1dF9vZmZfMikgJT4lIHNsaWNlKGNodWxsKGh3aSwgbWFzcykpCmh3aV9ieV9tYXNzX3VyYmFuXzEgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzEpICU+JSBzbGljZShjaHVsbChod2ksIG1hc3MpKQoKYmVha193aWR0aF9ieV9tYXNzX3VyYmFuXzMgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzMpICU+JSBzbGljZShjaHVsbChiZWFrX3dpZHRoLCBtYXNzKSkKYmVha193aWR0aF9ieV9tYXNzX3VyYmFuXzIgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzIpICU+JSBzbGljZShjaHVsbChiZWFrX3dpZHRoLCBtYXNzKSkKYmVha193aWR0aF9ieV9tYXNzX3VyYmFuXzEgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzEpICU+JSBzbGljZShjaHVsbChiZWFrX3dpZHRoLCBtYXNzKSkKCmh3aV9ieV9iZWFrX3dpZHRoX3VyYmFuXzMgPSBzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzMpICU+JSBzbGljZShjaHVsbChod2ksIGJlYWtfd2lkdGgpKQpod2lfYnlfYmVha193aWR0aF91cmJhbl8yID0gc3BlY2llc191cmJhbl9yZXNwb25zZSAlPiUgZmlsdGVyKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX3Byb3h5ID4gY3V0X29mZl8yKSAlPiUgc2xpY2UoY2h1bGwoaHdpLCBiZWFrX3dpZHRoKSkKaHdpX2J5X2JlYWtfd2lkdGhfdXJiYW5fMSA9IHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UgJT4lIGZpbHRlcihtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSA+IGN1dF9vZmZfMSkgJT4lIHNsaWNlKGNodWxsKGh3aSwgYmVha193aWR0aCkpCgpzcGVjaWVzX3VyYmFuX3Jlc3BvbnNlICU+JSBmaWx0ZXIobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkgPiBjdXRfb2ZmXzMpICU+JSBucm93KCkKc3BlY2llc191cmJhbl9yZXNwb25zZSAlPiUgZmlsdGVyKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX3Byb3h5ID4gY3V0X29mZl8yKSAlPiUgbnJvdygpCnNwZWNpZXNfdXJiYW5fcmVzcG9uc2UgJT4lIGZpbHRlcihtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSA+IGN1dF9vZmZfMSkgJT4lIG5yb3coKQpgYGAKCmBgYHtyfQpwb2x5Z29uX2xpbmVfdHlwZSA9ICdkYXNoZWQnCnBvbHlnb25fbGluZXdpZHRoID0gMC40CnBvbHlnb25fYWxwaGExID0gMC4wNQpwb2x5Z29uX2FscGhhMiA9IDAuMQpwb2x5Z29uX2FscGhhMyA9IDAuMTUKCmh3aV9ieV9tYXNzID0gZ2dwbG90KHNwZWNpZXNfdXJiYW5fcmVzcG9uc2UsIGFlcyh4ID0gaHdpLCB5ID0gbWFzcywgY29sb3VyID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkpKSArIAogIGdlb21fcG9seWdvbihkYXRhID0gaHdpX2J5X21hc3NfdXJiYW5fMSwgYWxwaGEgPSBwb2x5Z29uX2FscGhhMSwgY29sb3IgPSB0cmFpdF9wb2x5Z29uX2xpZ2h0LCBmaWxsID0gdHJhaXRfcG9seWdvbl9saWdodCwgbGluZXdpZHRoID0gcG9seWdvbl9saW5ld2lkdGgsIGxpbmV0eXBlID0gcG9seWdvbl9saW5lX3R5cGUpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh3aV9ieV9tYXNzX3VyYmFuXzIsIGFscGhhID0gcG9seWdvbl9hbHBoYTIsIGNvbG9yID0gdHJhaXRfcG9seWdvbl9tZWQsIGZpbGwgPSB0cmFpdF9wb2x5Z29uX21lZCwgbGluZXdpZHRoID0gcG9seWdvbl9saW5ld2lkdGgsIGxpbmV0eXBlID0gcG9seWdvbl9saW5lX3R5cGUpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh3aV9ieV9tYXNzX3VyYmFuXzMsIGFscGhhID0gcG9seWdvbl9hbHBoYTMsIGNvbG9yID0gdHJhaXRfcG9seWdvbl9kYXJrLCBmaWxsID0gdHJhaXRfcG9seWdvbl9kYXJrLCBsaW5ld2lkdGggPSBwb2x5Z29uX2xpbmV3aWR0aCwgbGluZXR5cGUgPSBwb2x5Z29uX2xpbmVfdHlwZSkgKwogIGdlb21fcG9pbnQoKSArIAogIGFidW5kYW5jZV9wcm94eV9zY2FsZSArCiAgbGFicyhjb2xvdXIgPSAiTWVhbiByZWxhdGl2ZSBhYnVuZGFuY2UgcHJveHkiLCB5ID0gJ01hc3MnLCB4ID0gJycpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsIGxlZ2VuZC50aXRsZS5wb3NpdGlvbiA9ICd0b3AnLCBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxMiwgJ21tJykpCgpiZWFrX3dpZHRoX2J5X21hc3MgPSBnZ3Bsb3Qoc3BlY2llc191cmJhbl9yZXNwb25zZSwgYWVzKHggPSBiZWFrX3dpZHRoLCB5ID0gbWFzcywgY29sb3VyID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfcHJveHkpKSArIAogIGdlb21fcG9seWdvbihkYXRhID0gYmVha193aWR0aF9ieV9tYXNzX3VyYmFuXzEsIGFscGhhID0gcG9seWdvbl9hbHBoYTEsIGNvbG9yID0gdHJhaXRfcG9seWdvbl9saWdodCwgZmlsbCA9IHRyYWl0X3BvbHlnb25fbGlnaHQsIGxpbmV3aWR0aCA9IHBvbHlnb25fbGluZXdpZHRoLCBsaW5ldHlwZSA9IHBvbHlnb25fbGluZV90eXBlKSArCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBiZWFrX3dpZHRoX2J5X21hc3NfdXJiYW5fMiwgYWxwaGEgPSBwb2x5Z29uX2FscGhhMiwgY29sb3IgPSB0cmFpdF9wb2x5Z29uX21lZCwgZmlsbCA9IHRyYWl0X3BvbHlnb25fbWVkLCBsaW5ld2lkdGggPSBwb2x5Z29uX2xpbmV3aWR0aCwgbGluZXR5cGUgPSBwb2x5Z29uX2xpbmVfdHlwZSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gYmVha193aWR0aF9ieV9tYXNzX3VyYmFuXzMsIGFscGhhID0gcG9seWdvbl9hbHBoYTMsIGNvbG9yID0gdHJhaXRfcG9seWdvbl9kYXJrLCBmaWxsID0gdHJhaXRfcG9seWdvbl9kYXJrLCBsaW5ld2lkdGggPSBwb2x5Z29uX2xpbmV3aWR0aCwgbGluZXR5cGUgPSBwb2x5Z29uX2xpbmVfdHlwZSkgKwogIGdlb21fcG9pbnQoKSArIAogIGFidW5kYW5jZV9wcm94eV9zY2FsZSArIAogIGxhYnMoeSA9ICcnLCB4ID0gJ0JlYWsgd2lkdGgnKQoKaHdpX2J5X2JlYWtfd2lkdGggPSBnZ3Bsb3Qoc3BlY2llc191cmJhbl9yZXNwb25zZSwgYWVzKHggPSBod2ksIHkgPSBiZWFrX3dpZHRoLCBjb2xvdXIgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9wcm94eSkpICsgCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBod2lfYnlfYmVha193aWR0aF91cmJhbl8xLCBhbHBoYSA9IHBvbHlnb25fYWxwaGExLCBjb2xvciA9IHRyYWl0X3BvbHlnb25fbGlnaHQsIGZpbGwgPSB0cmFpdF9wb2x5Z29uX2xpZ2h0LCBsaW5ld2lkdGggPSBwb2x5Z29uX2xpbmV3aWR0aCwgbGluZXR5cGUgPSBwb2x5Z29uX2xpbmVfdHlwZSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gaHdpX2J5X2JlYWtfd2lkdGhfdXJiYW5fMiwgYWxwaGEgPSBwb2x5Z29uX2FscGhhMiwgY29sb3IgPSB0cmFpdF9wb2x5Z29uX21lZCwgZmlsbCA9IHRyYWl0X3BvbHlnb25fbWVkLCBsaW5ld2lkdGggPSBwb2x5Z29uX2xpbmV3aWR0aCwgbGluZXR5cGUgPSBwb2x5Z29uX2xpbmVfdHlwZSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gaHdpX2J5X2JlYWtfd2lkdGhfdXJiYW5fMywgYWxwaGEgPSBwb2x5Z29uX2FscGhhMywgY29sb3IgPSB0cmFpdF9wb2x5Z29uX2RhcmssIGZpbGwgPSB0cmFpdF9wb2x5Z29uX2RhcmssIGxpbmV3aWR0aCA9IHBvbHlnb25fbGluZXdpZHRoLCBsaW5ldHlwZSA9IHBvbHlnb25fbGluZV90eXBlKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgYWJ1bmRhbmNlX3Byb3h5X3NjYWxlICsgCiAgbGFicyh5ID0gJ0JlYWsgd2lkdGgnLCB4ID0gJ0hXSScpCgpsZWdlbmQgPC0gZ2dwdWJyOjpnZXRfbGVnZW5kKAogICMgY3JlYXRlIHNvbWUgc3BhY2UgdG8gdGhlIGxlZnQgb2YgdGhlIGxlZ2VuZAogIGh3aV9ieV9tYXNzCikKCnBsb3RfZ3JpZCgKICBucm93ID0gMiwgbmNvbCA9IDIsCiAgaHdpX2J5X21hc3MgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICBiZWFrX3dpZHRoX2J5X21hc3MgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICBod2lfYnlfYmVha193aWR0aCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLAogIGxlZ2VuZAopCgpnZ3NhdmUoZmlsZW5hbWUoRklHVVJFU19PVVRQVVRfRElSLCAndHJhaXRzLmpwZycpLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE4MDAsIHVuaXRzID0gJ3B4JykKYGBgCg==